package com.cqkjxy.commons.validations;

import com.cqkjxy.commons.entities.AbstractEntity;
import com.cqkjxy.commons.validations.annotations.UniqueColumn;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.stereotype.Component;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.List;

@Component
public class UniqueColumnValidator implements ConstraintValidator<UniqueColumn, AbstractEntity> {

    protected static final transient Logger log = LoggerFactory.getLogger(UniqueColumnValidator.class);
    @PersistenceContext
    protected EntityManager entityManager;
    private String jpql;
    private String field;
    private String[] fields;

    @Override
    public void initialize(UniqueColumn annotation) {
        this.jpql = annotation.jpql();
        this.field = annotation.field();
        this.fields = annotation.fields();
    }

    @Override
    public boolean isValid(AbstractEntity entity, ConstraintValidatorContext context) {
        assert entity != null;
        assert entityManager != null;

        BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(entity);
        List<AbstractEntity> entities = null;
        try {
            if (!StringUtils.isBlank(field)) {
                Object propertyValue =  wrapper.getPropertyValue(field);
                if (propertyValue == null) {
                    return true;
                }

                entities = (List<AbstractEntity>) entityManager.createQuery(jpql)
                        .setParameter(1, propertyValue).getResultList();
            } else if (fields.length > 0) {
                Query query = entityManager.createQuery(jpql);
                for (int i = 0; i < fields.length; i++) {
                    Object propertyValue =  wrapper.getPropertyValue(fields[i]);
                    if (propertyValue == null) {
                        return true;
                    }

                    query.setParameter(i + 1, propertyValue);
                }
                entities = (List<AbstractEntity>) query.getResultList();
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("Can not get entity property", e);
            return false;
        }
        if (entities == null || entities.size() == 0) {
            return true;
        }

        if (entity.getPkId() == null) {
            return false;
        } else {
            for (AbstractEntity entityInDb : entities) {
                if (entity.getPkId().longValue() != entityInDb.getPkId().longValue()) {
                    return false;
                }
            }
        }

        return true;
    }
}

